/*
 * FengGUI - Java GUIs in OpenGL (http://www.fenggui.org)
 *
 * Copyright (c) 2005-2009 FengGUI Project
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details:
 * http://www.gnu.org/copyleft/lesser.html#TOC3
 *
 * Created on Aug 11, 2007
 * $Id$
 */
package fan.vaseOpenGl;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Hashtable;

public class ImageConverter
{

  public final static ComponentColorModel COLOR_MODEL = new ComponentColorModel(ColorSpace
                                                          .getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8, 8, 8 },
                                                          true, false, ComponentColorModel.TRANSLUCENT,
                                                          DataBuffer.TYPE_BYTE);

  public static BufferedImage createGlCompatibleAwtImage(int width, int height)
  {
    WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 4, null);
    BufferedImage convertImage = new BufferedImage(COLOR_MODEL, raster, false, new Hashtable<String, Object>());
    return convertImage;
  }

  public static boolean isGlCompatibleAwtImage(BufferedImage img)
  {
    if (img.getColorModel() != COLOR_MODEL)
      return false;
    if (!(img.getRaster().getDataBuffer() instanceof DataBufferByte))
      return false;
    //    if(img.getRaster().getDataBuffer().getNumBanks() != 4) return false;
    if (img.getRaster().getNumBands() != 4)
      return false;
    return true;
  }

  public static boolean isPowerOf2(int value)
  {
    int nearestPower = powerOf2(value);
    return value == nearestPower;
  }

  /**
   * Returns the closest (greater or equals) power of 2 to the given value.
   * @param value the value
   * @return power of 2
   */
  public static int powerOf2(int value)
  {
    if (value < 3)
      throw new IllegalArgumentException("value must be greater or equals 3!");

    int power = Integer.highestOneBit(value - 1);
    return 2 * power;
  }

  /**
   * Converts the given image to a gl compatible format if necessary and returns the data in the format GL_RGBA as GL_UNSIGNED_BYTE.
   * @param awtImage the image to be converted to an byte buffer
   * @return nio buffer
   */
  public static ByteBuffer convert(BufferedImage awtImage)
  {
    if (!isGlCompatibleAwtImage(awtImage))
    {
      BufferedImage convertImage = createGlCompatibleAwtImage(awtImage.getWidth(), awtImage.getHeight());
      // copy the source image into the produced image
      Graphics g = convertImage.getGraphics();
      g.setColor(new Color(0f, 0f, 0f, 0f));
      g.fillRect(0, 0, awtImage.getWidth(), awtImage.getHeight());
      g.drawImage(awtImage, 0, 0, null);
      awtImage = convertImage;
    }

    // build a byte buffer from the temporary image
    // that be used by OpenGL to produce a texture.
    byte[] data = ((DataBufferByte) awtImage.getRaster().getDataBuffer()).getData();
    ByteBuffer imageBuffer = ByteBuffer.allocateDirect(data.length);
    imageBuffer.order(ByteOrder.nativeOrder());
    imageBuffer.put(data, 0, data.length);
    imageBuffer.flip();

    return imageBuffer;
  }

  /**
   * Converts the given image to a gl compatible format if necessary and returns the data in the format GL_RGBA as GL_UNSIGNED_BYTE
   * such that the width and height are a power of 2. The image is place in the upper left corner.
   * @param awtImage the image to be converted to an byte buffer
   * @return nio buffer
   */
  public static ByteBuffer convertPowerOf2(BufferedImage awtImage)
  {
    if (!isGlCompatibleAwtImage(awtImage) || !isPowerOf2(awtImage.getWidth()) || !isPowerOf2(awtImage.getHeight()))
    {
      int width = powerOf2(awtImage.getWidth());
      int height = powerOf2(awtImage.getHeight());
      BufferedImage convertImage = createGlCompatibleAwtImage(width, height);
      // copy the source image into the produced image
      Graphics g = convertImage.getGraphics();
      g.setColor(new Color(0f, 0f, 0f, 0f));
      g.fillRect(0, 0, width, height);
      g.drawImage(awtImage, 0, 0, null);
      awtImage = convertImage;
    }

    // build a byte buffer from the temporary image
    // that be used by OpenGL to produce a texture.
    byte[] data = ((DataBufferByte) awtImage.getRaster().getDataBuffer()).getData();
    ByteBuffer imageBuffer = ByteBuffer.allocateDirect(data.length);
    imageBuffer.order(ByteOrder.nativeOrder());
    imageBuffer.put(data, 0, data.length);
    imageBuffer.flip();

    return imageBuffer;
  }

}